home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / tcpuser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  7.7 KB  |  348 lines

  1. /* User calls to TCP */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "timer.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "internet.h"
  9. #include "tcp.h"
  10. #include "ip.h"
  11. #include "icmp.h"
  12. #include "proc.h"
  13.  
  14. int16 Tcp_window = DEF_WND;
  15.  
  16. struct tcb *
  17. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  18. struct socket *lsocket;    /* Local socket */
  19. struct socket *fsocket;    /* Remote socket */
  20. int mode;        /* Active/passive/server */
  21. int16 window;        /* Receive window (and send buffer) sizes */
  22. void (*r_upcall)();    /* Function to call when data arrives */
  23. void (*t_upcall)();    /* Function to call when ok to send more data */
  24. void (*s_upcall)();    /* Function to call when connection state changes */
  25. int tos;
  26. int user;        /* User linkage area */
  27. {
  28.     struct connection conn;
  29.     struct tcb *tcb;
  30.  
  31.     if(lsocket == NULLSOCK){
  32.         Net_error = INVALID;
  33.         return NULLTCB;
  34.     }
  35.     conn.local.address = lsocket->address;
  36.     conn.local.port = lsocket->port;
  37.     if(fsocket != NULLSOCK){
  38.         conn.remote.address = fsocket->address;
  39.         conn.remote.port = fsocket->port;
  40.     } else {
  41.         conn.remote.address = 0;
  42.         conn.remote.port = 0;
  43.     }
  44.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  45.         if((tcb = create_tcb(&conn)) == NULLTCB){
  46.             Net_error = NO_MEM;
  47.             return NULLTCB;
  48.         }
  49.     } else if(tcb->state != TCP_LISTEN){
  50.         Net_error = CON_EXISTS;
  51.         return NULLTCB;
  52.     }
  53.     tcb->user = user;
  54.     if(window != 0)
  55.         tcb->window = tcb->rcv.wnd = window;
  56.     else
  57.         tcb->window = tcb->rcv.wnd = Tcp_window;
  58.     tcb->snd.wnd = 1;    /* Allow space for sending a SYN */
  59.     tcb->r_upcall = r_upcall;
  60.     tcb->t_upcall = t_upcall;
  61.     tcb->s_upcall = s_upcall;
  62.     tcb->tos = tos;
  63.     switch(mode){
  64.     case TCP_SERVER:
  65.         tcb->flags.clone = 1;
  66.     case TCP_PASSIVE:    /* Note fall-thru */
  67.         setstate(tcb,TCP_LISTEN);
  68.         break;
  69.     case TCP_ACTIVE:
  70.         /* Send SYN, go into TCP_SYN_SENT state */
  71.         tcb->flags.active = 1;
  72.         send_syn(tcb);
  73.         setstate(tcb,TCP_SYN_SENT);
  74.         tcp_output(tcb);
  75.     break;
  76.     }
  77.     return tcb;
  78. }
  79.  
  80. /* User send routine */
  81. int
  82. send_tcp(struct tcb *tcb,struct mbuf *bp)
  83. {
  84.     int16 cnt = len_p(bp);
  85.  
  86.     if(tcb == NULLTCB || bp == NULLBUF){
  87.         if(bp)
  88.             free_p(bp);
  89.         Net_error = INVALID;
  90.         return -1;
  91.     }
  92.  
  93.     switch(tcb->state){
  94.     case TCP_CLOSED:
  95.         free_p(bp);
  96.         Net_error = NO_CONN;
  97.         return -1;
  98.     case TCP_LISTEN:
  99.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  100.             /* Save data for later */
  101.             append(&tcb->sndq,bp);
  102.             tcb->sndcnt += cnt;
  103.             break;
  104.         }
  105.         /* Change state from passive to active */
  106.         tcb->flags.active = 1;
  107.         send_syn(tcb);
  108.         setstate(tcb,TCP_SYN_SENT);    /* Note fall-thru */
  109.     case TCP_SYN_SENT:
  110.     case TCP_SYN_RECEIVED:
  111.     case TCP_ESTABLISHED:
  112.     case TCP_CLOSE_WAIT:
  113.         append(&tcb->sndq,bp);
  114.         tcb->sndcnt += cnt;
  115.         tcp_output(tcb);
  116.         break;
  117.     case TCP_FINWAIT1:
  118.     case TCP_FINWAIT2:
  119.     case TCP_CLOSING:
  120.     case TCP_LAST_ACK:
  121.     case TCP_TIME_WAIT:
  122.         free_p(bp);
  123.         Net_error = CON_CLOS;
  124.         return -1;
  125.     }
  126.     return (int)cnt;
  127. }
  128.  
  129. /* User receive routine */
  130. int
  131. recv_tcp(struct tcb *tcb,struct mbuf **bpp,int16 cnt)
  132. {
  133.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  134.         Net_error = INVALID;
  135.         return -1;
  136.     }
  137.     if(tcb->rcvcnt == 0){
  138.         /* If there's nothing on the queue, our action depends on what state
  139.          * we're in (i.e., whether or not we're expecting any more data).
  140.          * If no more data is expected, then simply return 0; this is
  141.          * interpreted as "end of file". Otherwise return -1.
  142.          */
  143.         switch(tcb->state){
  144.         case TCP_LISTEN:
  145.         case TCP_SYN_SENT:
  146.         case TCP_SYN_RECEIVED:
  147.         case TCP_ESTABLISHED:
  148.         case TCP_FINWAIT1:
  149.         case TCP_FINWAIT2:
  150.             Net_error = WOULDBLK;
  151.             return -1;
  152.         case TCP_CLOSED:
  153.         case TCP_CLOSE_WAIT:
  154.         case TCP_CLOSING:
  155.         case TCP_LAST_ACK:
  156.         case TCP_TIME_WAIT:
  157.             *bpp = NULLBUF;
  158.             return 0;
  159.         }
  160.     }
  161.     /* cnt == 0 means "I want it all" */
  162.     if(cnt == 0)
  163.         cnt = tcb->rcvcnt;
  164.     /* See if the user can take all of it */
  165.     if(tcb->rcvcnt <= cnt){
  166.         cnt = tcb->rcvcnt;
  167.         *bpp = tcb->rcvq;
  168.         tcb->rcvq = NULLBUF;
  169.     } else {
  170.         *bpp = ambufw(cnt);
  171.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  172.         (*bpp)->cnt = cnt;
  173.     }
  174.     tcb->rcvcnt -= cnt;
  175.     tcb->rcv.wnd += cnt;
  176.     /* Do a window update if it was closed */
  177.     if(cnt == tcb->rcv.wnd){
  178.         tcb->flags.force = 1;
  179.         tcp_output(tcb);
  180.     }
  181.     return (int)cnt;
  182. }
  183.  
  184. /* This really means "I have no more data to send". It only closes the
  185.  * connection in one direction, and we can continue to receive data
  186.  * indefinitely.
  187.  */
  188. int
  189. close_tcp(struct tcb *tcb)
  190. {
  191.     if(tcb == NULLTCB){
  192.         Net_error = INVALID;
  193.         return -1;
  194.     }
  195.     switch(tcb->state){
  196.     case TCP_CLOSED:
  197.         return 0;    /* Unlikely */
  198.     case TCP_LISTEN:
  199.     case TCP_SYN_SENT:
  200.         close_self(tcb,NORMAL);
  201.         return 0;
  202.     case TCP_SYN_RECEIVED:
  203.     case TCP_ESTABLISHED:
  204.         tcb->sndcnt++;
  205.         tcb->snd.nxt++;
  206.         setstate(tcb,TCP_FINWAIT1);
  207.         tcp_output(tcb);
  208.         return 0;
  209.     case TCP_CLOSE_WAIT:
  210.         tcb->sndcnt++;
  211.         tcb->snd.nxt++;
  212.         setstate(tcb,TCP_LAST_ACK);
  213.         tcp_output(tcb);
  214.         return 0;
  215.     case TCP_FINWAIT1:
  216.     case TCP_FINWAIT2:
  217.     case TCP_CLOSING:
  218.     case TCP_LAST_ACK:
  219.     case TCP_TIME_WAIT:
  220.         Net_error = CON_CLOS;
  221.         return -1;
  222.     }
  223.     return -1;    /* "Can't happen" */
  224. }
  225.  
  226. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  227.  * not in the TCP_CLOSED state. This function should normally be called by the
  228.  * user only in response to a state change upcall to TCP_CLOSED state.
  229.  */
  230. int
  231. del_tcp(struct tcb *conn)
  232. {
  233.     struct tcb *tcb, *tcblast = NULLTCB;
  234.     struct reseq *rp, *rp1;
  235.  
  236.     /* Remove from list */
  237.     for(tcb=Tcbs;tcb != NULLTCB;tcblast = tcb,tcb = tcb->next)
  238.         if(tcb == conn)
  239.             break;
  240.     if(tcb == NULLTCB){
  241.         Net_error = INVALID;
  242.         return -1;    /* conn was NULL, or not on list */
  243.     }
  244.     if(tcblast != NULLTCB)
  245.         tcblast->next = tcb->next;
  246.     else
  247.         Tcbs = tcb->next;    /* was first on list */
  248.  
  249.     stop_timer(&tcb->timer);
  250.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  251.         rp1 = rp->next;
  252.         free_p(rp->bp);
  253.         xfree((char *)rp);
  254.     }
  255.     tcb->reseq = NULLRESEQ;
  256.     free_p(tcb->rcvq);
  257.     free_p(tcb->sndq);
  258.     xfree((char *)tcb);
  259.     return 0;
  260. }
  261.  
  262. /* Return 1 if arg is a valid TCB, 0 otherwise */
  263. int
  264. tcpval(struct tcb *tcb)
  265. {
  266.     struct tcb *tcb1;
  267.  
  268.     if(tcb == NULLTCB)
  269.         return 0;    /* Null pointer can't be valid */
  270.  
  271.     for(tcb1 = Tcbs; tcb1 != NULLTCB; tcb1 = tcb1->next){
  272.         if(tcb1 == tcb)
  273.             return 1;
  274.     }
  275.     return 0;
  276. }
  277.  
  278. /* Kick a particular TCP connection */
  279. int
  280. kick_tcp(struct tcb *tcb)
  281. {
  282.     if(!tcpval(tcb))
  283.         return -1;
  284.  
  285.     tcb->flags.force = 1;
  286.     tcp_timeout(tcb);
  287.     return 0;
  288. }
  289.  
  290. /* Kick all TCP connections to specified address; return number kicked */
  291. int
  292. kick(int32 addr)
  293. {
  294.     struct tcb *tcb;
  295.     int cnt = 0;
  296.  
  297.     for(tcb=Tcbs; tcb != NULLTCB; tcb = tcb->next){
  298.         if(tcb->conn.remote.address == addr){
  299.             kick_tcp(tcb);
  300.             cnt++;
  301.         }
  302.     }
  303.     return cnt;
  304. }
  305.  
  306. /* Clear all TCP connections */
  307. void
  308. reset_all()
  309. {
  310.     struct tcb *tcb, *tcbtmp = NULLTCB;
  311.  
  312.     for(tcb = Tcbs; tcb != NULLTCB; tcb = tcbtmp) {
  313.         tcbtmp = tcb->next;
  314.         reset_tcp(tcb);
  315.         pwait(NULL);        /* Let the RSTs go forth */
  316.     }
  317. }
  318.  
  319. void
  320. reset_tcp(tcb)
  321. struct tcb *tcb;
  322. {
  323.     struct tcp fakeseg;
  324.     struct ip fakeip;
  325.  
  326.     if(tcb == NULLTCB)
  327.         return;
  328.     if(tcb->state != TCP_LISTEN){
  329.         /* Compose a fake segment with just enough info to generate the
  330.          * correct RST reply
  331.          */
  332.         fakeseg.flags.rst = 0;
  333.         fakeseg.dest = tcb->conn.local.port;
  334.         fakeseg.source = tcb->conn.remote.port;
  335.         fakeseg.flags.ack = 1;
  336.         /* Here we try to pick a sequence number with the greatest likelihood
  337.          * of being in his receive window.
  338.          */
  339.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  340.         fakeip.dest = tcb->conn.local.address;
  341.         fakeip.source = tcb->conn.remote.address;
  342.         fakeip.tos = tcb->tos;
  343.         reset(&fakeip,&fakeseg);
  344.     }
  345.     close_self(tcb,RESET);
  346. }
  347.  
  348.